﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

public class TerrainMgrMono : MonoBehaviour
{
    public Transform target = null;
    // 单块地形的大小
    public int m_block_width = 100;
    public int m_block_height = 100;
    public int m_resolution = 64;
    // perlin噪音缩放系数
    public float m_scale = 30;

    Dictionary<Vector2Int, GameObject> m_terrain_map = new Dictionary<Vector2Int, GameObject>();

    Vector2Int m_last_position = new Vector2Int(-9999,-9999);

    private void Start()
    {
    }

    private void Update()
    {
        if (target == null) return;

        var pos = target.transform.position;
        var idx_pos = new Vector2Int(Mathf.FloorToInt(pos.x / m_block_width), Mathf.FloorToInt(pos.z / m_block_width));
        if(idx_pos != m_last_position)
        {
            // 位置发生改变
            m_last_position = idx_pos;
            // Remove
            RemoveSomeTerrain();
            // Add
            AddSomeTerrain();
        }
    }

    void RemoveSomeTerrain()
    {
        foreach(var it in m_terrain_map.ToList())
        {
            if(Mathf.Abs(it.Key.x-m_last_position.x) > 2
                || Mathf.Abs(it.Key.y - m_last_position.y) > 2)
            {
                m_terrain_map.Remove(it.Key);
                GameObject.Destroy(it.Value);
            }
        }
    }

    void AddSomeTerrain()
    {
        for(var i = m_last_position.x -1; i <= m_last_position.x + 1; i++)
            for(var j = m_last_position.y -1; j <= m_last_position.y+1;j++)
            {
                TryLoadTerrain(i, j);
            }
    }

    void TryLoadTerrain(int ix,int iy)
    {
        Vector2Int idx_v2 = new Vector2Int(ix, iy);
        if (m_terrain_map.ContainsKey(idx_v2)) return;

        TerrainData data = new TerrainData();
        data.heightmapResolution = m_resolution + 1;

        GameObject go = Terrain.CreateTerrainGameObject(data);
        go.name = "TerrainBlock:" + idx_v2;
        go.transform.position = new Vector3(idx_v2.x * m_block_width, 0, idx_v2.y * m_block_width);

        data.size = new Vector3(m_block_width, m_block_height, m_block_width);
        data.SetHeights(0, 0, GenerateHeights(ix,iy, data));

        m_terrain_map[idx_v2] = go;
    }

    float[,] GenerateHeights(int ix,int iy, TerrainData data)
    {
        ix *= m_block_width;
        iy *= m_block_width;
        var W = data.heightmapWidth;
        var H = data.heightmapHeight;
        float[,] heights = new float[W, H];
        for (int x = 0; x < W; x++)
        {
            for (int y = 0; y < H; y++)
            {
                heights[y, x] = CalculateHeight(ix+x*1.0f/(W-1)*m_block_width,iy+ y * 1.0f / (H-1) * m_block_width);
            }
        }
        return heights;
    }

    float CalculateHeight(float x, float y)
    {
        float xCoord = x / m_scale;
        float yCoord = y / m_scale;

        return Mathf.PerlinNoise(xCoord, yCoord);
    }

    #region 背景超大地形
    [Header("背景超大地形设置")]
    public int m_multiple = 100;
    TerrainData m_big_terrain = null;
    private void OnGUI()
    {
        if(GUILayout.Button("Gen Big Terrain"))
        {
            if (m_big_terrain == null)
            {
                m_big_terrain = new TerrainData();
                GameObject go = Terrain.CreateTerrainGameObject(m_big_terrain);
                go.name = "BigTerrain";
            }
            m_big_terrain.heightmapResolution = m_resolution*m_multiple;
            float width = m_block_width * m_multiple;
            m_big_terrain.size = new Vector3(width, m_block_height, width);

            var W = m_big_terrain.heightmapWidth;
            var H = m_big_terrain.heightmapHeight;
            float dw = width / (W - 1),dh = dw;
            float[,] heights = new float[W, H];
            for (int x = 0; x < W; x++)
            {
                for (int y = 0; y < H; y++)
                {
                    heights[y, x] = CalculateHeight(x * dw, y * dh);
                }
            }

            m_big_terrain.SetHeights(0, 0, heights);
        }
    }
    #endregion
}